import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';
import FormData from 'form-data';
import { ConfigService } from '@nestjs/config';
import {
  UploadMaterialDto,
  WechatMaterialType,
  UploadNewsDto,
} from './dto/upload-material.dto';

export interface WechatMessageDto {
  groupName: string;
  content: string;
}

export interface WechatTokenResponse {
  access_token: string;
  expires_in: number;
}

export interface WechatUploadResponse {
  media_id?: string;
  url?: string;
  item?: any;
  errcode?: number;
  errmsg?: string;
}

@Injectable()
export class WechatService {
  private readonly logger = new Logger(WechatService.name);
  private accessToken: string | null = null;
  private tokenExpireTime: number = 0;

  constructor(private readonly configService: ConfigService) {}

  /**
   * 获取微信公众号访问令牌
   */
  private async getAccessToken(): Promise<string> {
    const now = Date.now();
    // 如果令牌未过期，直接返回
    if (this.accessToken && this.tokenExpireTime > now) {
      return this.accessToken;
    }

    try {
      const appId = this.configService.get<string>('WECHAT_APP_ID');
      const appSecret = this.configService.get<string>('WECHAT_APP_SECRET');

      console.log(appId, appSecret);
      if (!appId || !appSecret) {
        throw new HttpException(
          '微信公众号配置缺失，请检查环境变量',
          HttpStatus.INTERNAL_SERVER_ERROR,
        );
      }

      const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`;
      const response = await axios.get<WechatTokenResponse>(url);

      if (response.data && response.data.access_token) {
        this.accessToken = response.data.access_token;
        // 设置过期时间，提前5分钟过期以确保安全
        this.tokenExpireTime = now + (response.data.expires_in - 300) * 1000;
        return this.accessToken;
      } else {
        throw new Error('获取微信访问令牌失败');
      }
    } catch (error) {
      this.logger.error('获取微信访问令牌出错', error);
      throw new HttpException(
        `获取微信访问令牌失败: ${error.message || '未知错误'}`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  /**
   * 下载文件
   * @param url 文件URL
   * @param fileName 文件名
   */
  private async downloadFile(url: string, fileName: string): Promise<string> {
    try {
      const tempDir = path.join(process.cwd(), 'temp');
      // 确保临时目录存在
      if (!fs.existsSync(tempDir)) {
        fs.mkdirSync(tempDir, { recursive: true });
      }

      const filePath = path.join(tempDir, fileName);
      const writer = fs.createWriteStream(filePath);

      const response = await axios({
        url,
        method: 'GET',
        responseType: 'stream',
      });

      response.data.pipe(writer);

      return new Promise((resolve, reject) => {
        writer.on('finish', () => resolve(filePath));
        writer.on('error', reject);
      });
    } catch (error) {
      this.logger.error(`下载文件失败: ${url}`, error);
      throw new HttpException(
        `下载文件失败: ${error.message || '未知错误'}`,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  /**
   * 上传素材到微信公众号
   * @param uploadDto 上传素材数据
   * @param isPermanent 是否为永久素材
   */
  async uploadMaterial(
    uploadDto: UploadMaterialDto,
    isPermanent: boolean = false,
  ): Promise<{
    success: boolean;
    message: string;
    data?: {
      media_id?: string;
      url?: string;
    };
  }> {
    try {
      const accessToken = await this.getAccessToken();
      const fileName = uploadDto.fileName || path.basename(uploadDto.fileUrl);
      const filePath = await this.downloadFile(uploadDto.fileUrl, fileName);

      // 根据是否为永久素材选择不同的API
      const apiUrl = isPermanent
        ? `https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${accessToken}&type=${uploadDto.type}`
        : `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${accessToken}&type=${uploadDto.type}`;

      const formData = new FormData();
      formData.append('media', fs.createReadStream(filePath));

      // 如果是视频素材，需要额外的描述信息
      if (uploadDto.type === WechatMaterialType.VIDEO && isPermanent) {
        const description = {
          title: uploadDto.title || fileName,
          introduction: uploadDto.introduction || '',
        };
        formData.append('description', JSON.stringify(description));
      }

      const response = await axios.post<WechatUploadResponse>(
        apiUrl,
        formData,
        {
          headers: {
            ...formData.getHeaders(),
          },
        },
      );

      // 删除临时文件
      fs.unlinkSync(filePath);

      if (response.data.errcode) {
        this.logger.error(`上传微信素材失败: ${JSON.stringify(response.data)}`);
        return {
          success: false,
          message: `上传微信素材失败: ${response.data.errmsg || JSON.stringify(response.data)}`,
        };
      }

      this.logger.log(`成功上传微信素材: ${uploadDto.type}`);
      return {
        success: true,
        message: '上传微信素材成功',
        data: {
          media_id: response.data.media_id,
          url: response.data.url,
        },
      };
    } catch (error) {
      this.logger.error('上传微信素材出错', error);
      return {
        success: false,
        message: `上传微信素材出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 上传图文素材到微信公众号
   * @param uploadDto 上传图文素材数据
   */
  async uploadNews(uploadDto: UploadNewsDto): Promise<{
    success: boolean;
    message: string;
    data?: {
      media_id?: string;
    };
  }> {
    try {
      const accessToken = await this.getAccessToken();
      const apiUrl = `https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=${accessToken}`;

      const response = await axios.post<WechatUploadResponse>(
        apiUrl,
        { articles: uploadDto.articles },
        {
          headers: {
            'Content-Type': 'application/json',
          },
        },
      );

      if (response.data.errcode) {
        this.logger.error(
          `上传微信图文素材失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          message: `上传微信图文素材失败: ${response.data.errmsg || JSON.stringify(response.data)}`,
        };
      }

      this.logger.log(`成功上传微信图文素材`);
      return {
        success: true,
        message: '上传微信图文素材成功',
        data: {
          media_id: response.data.media_id,
        },
      };
    } catch (error) {
      this.logger.error('上传微信图文素材出错', error);
      return {
        success: false,
        message: `上传微信图文素材出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 发送微信消息
   * @param messageDto 消息数据
   */
  async sendMessage(messageDto: WechatMessageDto): Promise<{
    success: boolean;
    message: string;
  }> {
    try {
      const response = await axios.post(
        'http://14.103.232.62:4000/wechat/send',
        messageDto,
        {
          headers: {
            'Content-Type': 'application/json',
          },
        },
      );

      // 判断响应状态码和响应内容
      if (response.status === 200 || response.status === 201) {
        // 如果响应中包含 success 字段，则使用该字段判断
        if (
          response.data &&
          typeof response.data === 'object' &&
          'success' in response.data
        ) {
          if (
            response.data.success === true ||
            response.data.success === 'true'
          ) {
            this.logger.log(`成功发送微信消息到群组: ${messageDto.groupName}`);
            return {
              success: true,
              message: response.data.message || '发送微信消息成功',
            };
          } else {
            this.logger.error(
              `发送微信消息失败: ${JSON.stringify(response.data)}`,
            );
            return {
              success: false,
              message:
                response.data.message ||
                `发送微信消息失败: ${JSON.stringify(response.data)}`,
            };
          }
        } else {
          // 如果响应中没有 success 字段，则默认为成功
          this.logger.log(`成功发送微信消息到群组: ${messageDto.groupName}`);
          return {
            success: true,
            message:
              typeof response.data === 'string'
                ? response.data
                : JSON.stringify(response.data),
          };
        }
      } else {
        this.logger.error(`发送微信消息失败: ${JSON.stringify(response.data)}`);
        return {
          success: false,
          message: `发送微信消息失败: ${JSON.stringify(response.data)}`,
        };
      }
    } catch (error: any) {
      this.logger.error('发送微信消息出错', error);
      return {
        success: false,
        message: `发送微信消息出错: ${error.message || '未知错误'}`,
      };
    }
  }
}
